using HCP.Responses;
using HCP.SimpleJSON;
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;

namespace HCP.Requests
{
    public class FindElement : JobRequest
    {
        public string Strategy => base.Data["strategy"];

        public string Selector => base.Data["selector"];

        public string Context => base.Data["context"];

        public bool Multiple => base.Data["multiple"].AsBool;

        public FindElement(JSONClass json)
            : base(json)
        {
        }

        protected Type GetType(string typeName)
        {
            Type type = Type.GetType(typeName);
            if (type != null)
            {
                return type;
            }
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assembly in assemblies)
            {
                type = assembly.GetType(typeName);
                if (type != null)
                {
                    return type;
                }
            }
            return null;
        }

        protected JobResponse ProcessSingle()
        {
            GameObject gameObject = null;
            Component component = null;
            string text = null;
            string objectPart = ElementId.ObjectPart(Selector);
            string text2 = ElementId.ComponentPart(Selector);
            if (!string.IsNullOrEmpty(objectPart))
            {
                string strategy = Strategy;
                switch (strategy)
                {
                    case "name":
                        gameObject = Resources.FindObjectsOfTypeAll<GameObject>().First((GameObject g) => g.name == objectPart);
                        UnityEngine.Debug.Log(gameObject.name);
                        break;
                    case "id":
                        gameObject = JobRequest.GetElementById(objectPart).gameObject;
                        break;
                    case "tag name":
                        gameObject = Resources.FindObjectsOfTypeAll<GameObject>().First((GameObject g) => g.tag == objectPart).gameObject;
                        break;
                    case "class name":
                        {
                            if (ElementId.HasComponentPart(Selector))
                            {
                                throw new ArgumentException("Find strategy type class name cannot have component part: " + Selector);
                            }
                            Type type = GetType(objectPart);
                            component = Resources.FindObjectsOfTypeAll<Component>().First((Component c) => c.GetComponent(type) != null);
                            break;
                        }
                    case "xpath":
                        gameObject = GameObject.Find(objectPart);
                        break;
                    default:
                        throw new ArgumentException("Find strategy type unsupported: " + Strategy);
                }
            }
            if (gameObject != null && component == null)
            {
                component = gameObject.GetComponent(text2);
            }
            if (component != null)
            {
                text = JobRequest.ConstructElementId(component);
                JobRequest.RegisterElement(text, component);
                return JSONResponse.FromObject(new
                {
                    ELEMENT = text
                });
            }
            throw new ArgumentException("Could not find <" + text2 + "> on <" + objectPart + ">");
        }

        protected JobResponse ProcessMultiple()
        {
            string[] array = null;
            GameObject[] array2 = null;
            Component[] array3 = null;
            string componentPart = ElementId.ComponentPart(Selector);
            string objectPart = ElementId.ObjectPart(Selector);
            if (!string.IsNullOrEmpty(componentPart))
            {
                throw new ArgumentException("FindElement - Multiple strategy does not currently support component selection");
            }
            string strategy = Strategy;
            switch (strategy)
            {
                case "name":
                    array2 = (from g in Resources.FindObjectsOfTypeAll<GameObject>()
                              where g.name == objectPart
                              select g).ToArray();
                    break;
                case "id":
                    throw new ArgumentException("FindElement - You cannot find multiple of the same id");
                case "tag name":
                    array2 = (from g in Resources.FindObjectsOfTypeAll<GameObject>()
                              where g.tag == objectPart
                              select g).ToArray();
                    break;
                case "class name":
                    {
                        if (ElementId.HasComponentPart(Selector))
                        {
                            throw new ArgumentException("Find strategy type class name cannot have component part: " + Selector);
                        }
                        Type type = GetType(objectPart);
                        array3 = (from c in Resources.FindObjectsOfTypeAll<Component>()
                                  where c.GetComponent(type) != null
                                  select c).ToArray();
                        break;
                    }
                case "xpath":
                    throw new NotImplementedException("FindElement - Do not currently support xpath");
                default:
                    throw new ArgumentException("Find strategy type unsupported: " + Strategy);
            }
            if (array2 != null && array3 == null)
            {
                array3 = (from g in array2
                          where g.GetComponent(componentPart) != null
                          select g.GetComponent(componentPart)).ToArray();
            }
            if (array3 != null)
            {
                array = (from g in array3
                         select JobRequest.ConstructElementId(g.GetComponent(componentPart))).ToArray();
                return JSONResponse.FromArray(array, (object item) => new
                {
                    ELEMENT = item
                });
            }
            throw new ArgumentException("Could not find <" + componentPart + "> on <" + objectPart + ">");
        }

        public override JobResponse Process()
        {
            if (Multiple)
            {
                return ProcessMultiple();
            }
            return ProcessSingle();
        }
    }
}
